#!/usr/bin/env bash

# This script is used to export images from registry to local storage.
#
# Usage:
# export-images.sh <directory>

# whether repository specified be in EXCLUDES
# param 1: repository specified to judge
# return : 0 - in; 1 - not in; 2 - param error
function is_exclude()
{
  if [ $# -ne 1 ]; then
    echo 2
    return
  fi

  for exclude in ${EXCLUDES[@]}; do
    if [ x${1} == x${exclude} ]; then
      echo 0
      return
    fi
  done

  echo 1
}

# get all cataloges from hub, no version found
function get_cataloges()
{
  local RET

  RET=$(curl --key ${KEY_FILE} -s ${REGISTRY_URI}/_catalog)
  RET=${RET#*[} # remove prefix
  RET=${RET%]\}}  # remove suffix

  # output all cataloges, one catalog per line.
  # they can be used as array, or piped with awk
  echo ${RET} | sed 's/,/\n/g; s/"//g' | sort
}

# get tags by catalog specified.
# param 1: repository specified
function get_tags()
{
  [ $# -ne 1 ] && return

  local -r REPO=${1}
  local RET=$(curl --key ${KEY_FILE} -X GET -s ${REGISTRY_URI}/${REPO}/tags/list)
  RET=${RET#*[} # remove prefix
  RET=${RET%]\}} # remove suffix

  # output all tags according repository specified,
  # one tag per line.
  # DOCKER_HUB/repo:tag is a full image url
  # they can be used as array, or piped with awk
  echo ${RET} | sed 's/,/\n/g; s/"//g' | sort
}

# export one image from hub to local storage.
# param 1: repository
# param 2: tag
function export_one()
{
  [ $# -ne 2 ] && return

  local -r REPO=${1}
  local -r TAG=${2}

  local -r ORI_IMAGE_NAME="${REPO}:${TAG}"
  local -r HUB_IMAGE_NAME="${DOCKER_HUB}/${ORI_IMAGE_NAME}"

  echo "-------------------------------------------------"
  echo "Pulling image ${ORI_IMAGE_NAME}..."
  docker pull ${HUB_IMAGE_NAME}
  echo ""

  if [ $(is_exclude ${ORI_IMAGE_NAME}) -ne 0 ]; then
    echo -n "Retag image ${HUB_IMAGE_NAME} to ${ORI_IMAGE_NAME}..."
    docker tag ${HUB_IMAGE_NAME} ${ORI_IMAGE_NAME}
    echo "ok"
  fi

  echo -n "Preparing directory..."
  sudo mkdir -p ${LOCAL_DIR}/${REPO}
  sudo rmdir ${LOCAL_DIR}/${REPO}
  echo "ok"

  echo -n "Export image ${ORI_IMAGE_NAME}..."
  docker save ${ORI_IMAGE_NAME} -o ${LOCAL_DIR}/${REPO}_${TAG}.image.tar
  echo "ok"
  echo ""

  if [ $(is_exclude ${ORI_IMAGE_NAME}) -ne 0 ]; then
    echo "Removing local image ${ORI_IMAGE_NAME}..."
    docker rmi ${HUB_IMAGE_NAME} ${ORI_IMAGE_NAME}
    echo ""
  fi
}

function do_export()
{
  local -ar CATALOGS=($(get_cataloges))
  local -a TAGS
  for repo in ${CATALOGS[@]}; do
    # get tags according catalog
    TAGS=($(get_tags ${repo}))
    for tag in ${TAGS[@]}; do
      # export catalog:tag per tag
      #   mkdir -p with name of <output directory>/<catalog>
      #   then rmdir <dir> created upon, remain sub-dir within name of catalog
      #   docker pull image, the name start with DOCKER_HUB, then retag it to remove suffix.
      #   docker save
      #   after all, the image has been saved to local storage from hub across 'docker pull'
      export_one ${repo} ${tag}
    done
  done
}

# --- declare variables ---
set -e
declare -r DOCKER_HUB="docker-hub:5000"
declare -r REGISTRY_URI="https://${DOCKER_HUB}/v2"
declare -r LOCAL_DIR=${1}
declare -ar EXCLUDES=(
  "registry:2.7.1"
)
declare -r SSL_DIR="/opt/ssl/registry"
declare -r CA_FILE="${SSL_DIR}/ca.crt"
declare -r CERT_FILE="${SSL_DIR}/registry.pem"
declare -r KEY_FILE="${SSL_DIR}/registry.key"

# --- main script ---
if [ $# -ne 1 ]; then
  echo "Usage: export-image.sh <directory>"
  exit 1
fi
if [ ! -d ${1} ]; then
  echo " the directory ${1} must be exist!"
  exit 2
fi

do_export
